package com.ice_col.nfcdemo;

import android.app.PendingIntent;
import android.content.Intent;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.IsoDep;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.Html;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.Arrays;

public class MainActivity extends AppCompatActivity {

    private final static byte[] DFN_SRV = {(byte) 'P', (byte) 'A', (byte) 'Y',
            (byte) '.', (byte) 'S', (byte) 'Z', (byte) 'T'};

    protected final static byte[] DFN_PSE = {(byte) '1', (byte) 'P',
            (byte) 'A', (byte) 'Y', (byte) '.', (byte) 'S', (byte) 'Y',
            (byte) 'S', (byte) '.', (byte) 'D', (byte) 'D', (byte) 'F',
            (byte) '0', (byte) '1',};
    protected final static int MAX_LOG = 10;
    protected final static int SFI_EXTRA = 21;
    protected final static int SFI_LOG = 24;
    protected final static byte TRANS_CSU = 6;
    protected final static byte TRANS_CSU_CPX = 9;


    private NfcAdapter mNfcAdapter;
    private PendingIntent mPendingItent;
    private TextView tv_cash;
    private TextView tv_date;
    private TextView tv_log;
    private TextView tv_serl;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mNfcAdapter = NfcAdapter.getDefaultAdapter(this);

        mPendingItent = PendingIntent.getActivity(this, 0,
                new Intent(this, getClass()), 0);


    }


    private void initView() {
        tv_cash = (TextView) findViewById(R.id.nfc_tv_cash);
        tv_date = (TextView) findViewById(R.id.nfc_tv_date);
        tv_log = (TextView) findViewById(R.id.nfc_tv_log);
        tv_serl = (TextView) findViewById(R.id.nfc_tv_serl);

    }

    @Override
    protected void onResume() {
        super.onResume();
        if (mNfcAdapter != null) {
            mNfcAdapter.enableForegroundDispatch(this, mPendingItent, null, null);
        }


    }

    @Override
    protected void onPause() {
        super.onPause();
        if (mNfcAdapter != null) {
            mNfcAdapter.disableForegroundDispatch(this);
        }
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        if (tag == null) {
            Toast.makeText(this, "not writeable!", Toast.LENGTH_SHORT).show();
            return;
        } else {
            Toast.makeText(this, "Tag detected!", Toast.LENGTH_SHORT).show();
        }
        tagMethodTest(tag);
        initView();
        readInfo(tag);
        showInformation();
    }

    private void showInformation(){
        tv_serl.setText("卡号：" + serl);
        tv_cash.setText("余额：" + cash);
        tv_date.setText("消费日期：" + date);
        tv_log.setText("消费记录：" + Html.fromHtml(log));
    }

    private void tagMethodTest(Tag tag) {
        /*
        int 	describeContents()
        Describe the kinds of special objects contained in this Parcelable's marshalled representation.
        */
        int desContents = tag.describeContents();
        System.out.println("describeContents:" + desContents);
        System.out.println("*************");
        /*
        byte[] 	getId()
        Get the Tag Identifier (if it has one).
        */
        byte[] id = tag.getId();
        System.out.println("id:");
        for (int i = 0; i < id.length; i++) {
            System.out.print(id[i]);
        }

        System.out.println();
        System.out.println("*************");
        /*
        String[] 	getTechList()
        Get the technologies available in this tag, as fully qualified class names.
        */
        String[] techList = tag.getTechList();
        System.out.println("techList:");
        for (int i = 0; i < techList.length; i++) {
            System.out.println(techList[i]);
        }
        System.out.println("*************");
        /*
        String 	toString()
        Human-readable description of the tag, for debugging.
        void 	writeToParcel(Parcel dest, int flags)
        Flatten this object in to a Parcel.
         */
        System.out.println(tag.toString());
        System.out.println("*************");
    }



    private void readInfo(Tag tag) {


        //shenzhentong surport IsoDep & NfcA technology
        final IsoDep isodep = IsoDep.get(tag);

        //Iso7816 is a kind of Protocol
        final Iso7816.Tag iso7816Tag = new Iso7816.Tag(isodep);

        iso7816Tag.connect();
        if (iso7816Tag.selectByName(DFN_PSE).isOkey() && iso7816Tag.selectByName(DFN_SRV).isOkey()) {
            Iso7816.Response INFO, CASH;
            INFO = iso7816Tag.readBinary(SFI_EXTRA);
            System.out.println("Info:" + INFO.toString());
            CASH = iso7816Tag.getBalance(true);
            ArrayList<byte[]> LOG = readLog(iso7816Tag, SFI_LOG);

            parseBalance(CASH);
            parseInfo(INFO, 4, true);
            parseLog(LOG);
        } else {
            Toast.makeText(MainActivity.this, "Not support yet!", Toast.LENGTH_LONG).show();
        }

    }


    protected String name;
    protected String id;
    protected String serl;
    protected String version;
    protected String date;
    protected String count;
    protected String cash;
    protected String log;


    protected void parseInfo(Iso7816.Response data, int dec, boolean bigEndian) {
        if (!data.isOkey() || data.size() < 30) {
            serl = version = date = count = null;
            return;
        }

        final byte[] d = data.getBytes();
        if (dec < 1 || dec > 10) {
            serl = Util.toHexString(d, 10, 10);
        } else {
            final int sn = bigEndian ? Util.toIntR(d, 19, dec) : Util.toInt(d,
                    20 - dec, dec);

            serl = String.format("%d", 0xFFFFFFFFL & sn);
        }

        version = (d[9] != 0) ? String.valueOf(d[9]) : null;
        date = String.format("%02X%02X.%02X.%02X - %02X%02X.%02X.%02X", d[20],
                d[21], d[22], d[23], d[24], d[25], d[26], d[27]);
        count = null;
        System.out.println("date:" + date);
        System.out.println("serl:" + serl);
        System.out.println("version:" + version);
    }

    protected static boolean addLog(final Iso7816.Response r,
                                    ArrayList<byte[]> l) {
        if (!r.isOkey())
            return false;

        final byte[] raw = r.getBytes();
        final int N = raw.length - 23;
        if (N < 0)
            return false;

        for (int s = 0, e = 0; s <= N; s = e) {
            l.add(Arrays.copyOfRange(raw, s, (e = s + 23)));
        }

        return true;
    }

    protected static ArrayList<byte[]> readLog(Iso7816.Tag tag, int sfi) {
        final ArrayList<byte[]> ret = new ArrayList<byte[]>(MAX_LOG);
        final Iso7816.Response rsp = tag.readRecord(sfi);
        if (rsp.isOkey()) {
            addLog(rsp, ret);
        } else {
            for (int i = 1; i <= MAX_LOG; ++i) {
                if (!addLog(tag.readRecord(sfi, i), ret))
                    break;
            }
        }

        return ret;
    }

    protected void parseLog(ArrayList<byte[]>... logs) {
        final StringBuilder r = new StringBuilder();

        for (final ArrayList<byte[]> log : logs) {
            if (log == null)
                continue;

            if (r.length() > 0)
                r.append("<br />--------------");

            for (final byte[] v : log) {
                final int cash = Util.toInt(v, 5, 4);
                if (cash > 0) {
                    r.append("<br />").append(
                            String.format("%02X%02X.%02X.%02X %02X:%02X ",
                                    v[16], v[17], v[18], v[19], v[20], v[21],
                                    v[22]));

                    final char t = (v[9] == TRANS_CSU || v[9] == TRANS_CSU_CPX) ? '-'
                            : '+';

                    r.append(t).append(Util.toAmountString(cash / 100.0f));

                    final int over = Util.toInt(v, 2, 3);
                    if (over > 0)
                        r.append(" [o:")
                                .append(Util.toAmountString(over / 100.0f))
                                .append(']');

                    r.append(" [").append(Util.toHexString(v, 10, 6))
                            .append(']');
                }
            }
        }

        this.log = r.toString();
        System.out.println("log:" + log);
    }

    protected void parseBalance(Iso7816.Response data) {
        if (!data.isOkey() || data.size() < 4) {
            cash = null;
            return;
        }

        int n = Util.toInt(data.getBytes(), 0, 4);
        if (n > 100000 || n < -100000)
            n -= 0x80000000;

        cash = Util.toAmountString(n / 100.0f);

        System.out.println("cash:" + cash);
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}
